//
//  TouchView.m
//  CircleTest
//
//  Created by iphone user on 4/5/10.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "gestureOverlay.h"
#import <math.h>

@implementation gestureOverlay
@synthesize points,ctrl;
@synthesize drawGesture, gestureController, accelerometer;

- (BOOL) isMultipleTouchEnabled {return NO;}



float slope (CGPoint v1, CGPoint v2)
{
	float m= ((v2.y - v1.y)/(v2.x - v1.x));
	return m;
}

float intercept(CGPoint v, float m)
{
	return (v.y - m*v.x);
}

float lineDistance(CGPoint v, float m, float b)
{
	float d = ABS(m*v.x - v.y +b)/sqrt((m*m)-1);
	return d;
}

// Return dot product of two vectors normalized
float dotproduct (CGPoint v1, CGPoint v2)
{
	float dot = (v1.x * v2.x) + (v1.y * v2.y);
	float a = ABS(sqrt(v1.x * v1.x + v1.y * v1.y));
	float b = ABS(sqrt(v2.x * v2.x + v2.y * v2.y));
	dot /= (a * b);
	
	return dot;
}

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
	
	
	float xx = acceleration.x;
	float yy = acceleration.y;
	float zz = acceleration.z;
	
	if(!first)
	{
		/* float dot = (px * xx) + (py * yy) + (pz * zz);
		 float a = ABS(sqrt(px * px + py * py + pz * pz));
		 float b = ABS(sqrt(xx * xx + yy * yy + zz * zz));
		 dot /= (a * b);
		 */
		float dot = dotproduct(CGPointMake(xx,yy), CGPointMake(px,py));
		if (dot < sensitivity) // bounce
		{
			if (!isChange)
			{
				isChange = YES;
			if( gestureController!=nil)
			{
				if(dir>0)
				{
					[gestureController onGesture:kFlipOut];
				}
				else
				{
					[gestureController onGesture:kFlipIn];
				}
			}
			}
		} 
		else
		{
			isChange = NO;
		}
	}
	dir = yy-xx;
	px = xx; py = yy; pz = zz;
	first =NO;
}

-(id) initWithView:(UIView *) parent
{
	self = [super initWithFrame:parent.bounds];
	if(self!=nil)
	{
		self.opaque=NO;
		self.drawGesture=YES;
		numberOfCircles=0;
		prevSlope=0;
		self.accelerometer = [UIAccelerometer sharedAccelerometer];
		self.accelerometer.updateInterval = .1;
		self.accelerometer.delegate = self;
		first=YES;
		isChange=NO;
		sensitivity = -0.4f;
	}
	return self;
}

// Return distance between two points
float distance (CGPoint p1, CGPoint p2)
{
	float dx = p2.x - p1.x;
	float dy = p2.y - p1.y;
	
	return sqrt(dx*dx + dy*dy);
}

// Calculate and return least bounding rectangle
- (CGRect) centeredRectangle
{
	float x = 0.0f;
	float y = 0.0f;
	for (NSValue *pt in self.points)
	{
		x += [pt CGPointValue].x;
		y += [pt CGPointValue].y;
	}
	
	// Calculate weighted center
	x /= self.points.count;
	y /= self.points.count;
	
	float minx = 9999.0f;
	float maxx = -9999.0f;
	float miny = 9999.0f;
	float maxy = -9999.0f;
	
	for (NSValue *pt in self.points)
	{
		minx = MIN(minx, [pt CGPointValue].x);
		miny = MIN(miny, [pt CGPointValue].y);
		maxx = MAX(maxx, [pt CGPointValue].x);
		maxy = MAX(maxy, [pt CGPointValue].y);
	}
	
	return CGRectMake(minx, miny, (maxx - minx), (maxy - miny));
}

// Return a point with respect to a given origin
CGPoint centerPoint(CGPoint pt, CGPoint origin)
{
	return CGPointMake(pt.x - origin.x, pt.y - origin.y);
}

// On new touch, start a new array of points
- (void) touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event
{
	self.points = [NSMutableArray array];
	CGPoint pt = [[touches anyObject] locationInView:self];
	[self.points addObject:[NSValue valueWithCGPoint:pt]];
	CGPoint tapPoint = [[touches anyObject] locationInView: self.superview];
	ctrl=nil;
	numberOfCircles=0;
	
	for (UIView* subview in self.superview.subviews) {		
		if([subview isKindOfClass:[UIControl class]] 
		   && [subview pointInside: [self.superview convertPoint:tapPoint toView:subview] withEvent:event]){
			ctrl = (UIControl *)subview;
			track= [ctrl beginTrackingWithTouch:[touches anyObject] withEvent:event];
			break;
		}
	}
}

// Add each point to the array
- (void) touchesMoved:(NSSet *) touches withEvent:(UIEvent *) event
{
	CGPoint pt = [[touches anyObject] locationInView:self];
	[self.points addObject:[NSValue valueWithCGPoint:pt]];
	[self setNeedsDisplay];
	CGPoint tapPoint = [[touches anyObject] locationInView: self.superview];
	
	if( ![ctrl pointInside: [self.superview convertPoint:tapPoint toView:(UIView *)ctrl] withEvent:event])
	{
		track = NO;
		[ctrl cancelTrackingWithEvent:event];
	}
	if(track)
	{
		track=[ctrl continueTrackingWithTouch:[touches anyObject] withEvent:event];
	}
	
}

- (void) touchesEnded:(NSSet *) touches withEvent:(UIEvent *) event
{
	if (!self.points) return;
	if (self.points.count < 2){
		if(track)
		{
			[ctrl endTrackingWithTouch:[touches anyObject] withEvent:event];
			[ctrl sendActionsForControlEvents:[ctrl allControlEvents]];
			[ctrl cancelTrackingWithEvent:event];
			track=NO;
		}
	
	return;
	}		
	
	numberOfCircles=0;
	
	CGRect tcircle;
	if (distance(POINT(0), POINT(self.points.count - 1)) < 200.0f)
	{
		tcircle = [self centeredRectangle];
	}
	
	float m,b;
	BOOL canBeLine = YES;
	
	m=slope(POINT(0),POINT(self.points.count -1));
	b=intercept(POINT(0),m);
	
	// Test 2: Count the distance traveled in degrees. Must fall within 45 degrees of 2 PI
	CGPoint center = CGPointMake(CGRectGetMidX(tcircle), CGRectGetMidY(tcircle));
	float deg = ABS(acos(dotproduct(centerPoint(POINT(0), center), centerPoint(POINT(1), center))));
	for (int i = 1; i < (self.points.count - 1); i++)
	{
	
		deg += ABS(acos(dotproduct(centerPoint(POINT(i), center), centerPoint(POINT(i+1), center))));
		
		if((ABS(deg - 2 * M_PI) < (M_PI/4.0)))
		{
			numberOfCircles++; 
			deg=0;
		}
		
		if(canBeLine)
		{
				if(lineDistance(POINT(i), m, b)>100)
				{
					canBeLine=NO;
				}
		}
	}
	
	GESTURES gesture=kNoGesture;
	if(numberOfCircles >0)
	{
		circle =tcircle;
		if(circle.size.width>0)
		{
			gesture = kCircle;
			prevSlope =0;
		}
	}
	else if(canBeLine && (distance(POINT(0), POINT(self.points.count - 1)) > 100.0f))
	{
		
		float angle=(atan(m)*180/M_PI);
		
		if( (90.0- ABS(angle)) < 30  )
		{
			if(POINT(0).y> POINT(self.points.count - 1).y)
			{
				gesture =kLineUp;
			}
			else
			{
				gesture = kLineDown;
			}
			prevSlope=0;
		}
		else if(ABS(angle) < 10)
		{
			if(POINT(0).x> POINT(self.points.count - 1).x)
			{
				gesture =kLineLeft;
			}
			else
			{
				gesture = kLineRight;
			}		
			prevSlope=0;
		}
		else
		{
			if(prevSlope !=0 && (prevSlope * (angle/ABS(angle))) < 0)
			{
					gesture =kCross;
					prevSlope=0;
			}
			else
			{
				prevSlope = angle/ABS(angle);
			}
		}
	
	}
	else if (track){
	
		NSLog(@"%d",numberOfCircles);
		[ctrl endTrackingWithTouch:[touches anyObject] withEvent:event];
		[ctrl sendActionsForControlEvents:[ctrl allControlEvents]];
		[ctrl cancelTrackingWithEvent:event];
		track=NO;
	}
	if(gesture!=kNoGesture &&  gestureController!=nil)
		[gestureController onGesture:gesture];
	
	numberOfCircles=0;
	[self setNeedsDisplay];
}

// Show all points plus the current circle and its center
- (void) drawRect: (CGRect) rect
{
	
	
	if(drawGesture)
	{
		CGContextRef context = UIGraphicsGetCurrentContext();
	
	// draw circle
	[[UIColor redColor] set];
	CGContextAddEllipseInRect(context, circle);
	CGContextStrokePath(context);
	
	// draw center
	CGPoint center = CGPointMake(CGRectGetMidX(circle), CGRectGetMidY(circle));
	CGRect crect = CGRectMake(center.x - 2.0f, center.y - 2.0f, 4.0f, 4.0f);
	CGContextAddEllipseInRect(context, crect);
	CGContextFillPath(context);
	
	// Show the original shape
	if (self.points.count < 2) return;
	
	[[UIColor blackColor] set];
	CGContextSetLineWidth(context, 3.0f);
	for (int i = 0; i < (self.points.count - 1); i++)
	{
		CGPoint pt1 = [[self.points objectAtIndex:i] CGPointValue];
		CGPoint pt2 = [[self.points objectAtIndex:(i+1)] CGPointValue];
		CGContextMoveToPoint(context, pt1.x, pt1.y);
		CGContextAddLineToPoint(context, pt2.x, pt2.y);
		CGContextStrokePath(context);
	}
	}
	// Reset circle
	circle = CGRectZero;

}
@end
